namespace SubhadraSolutions.Sharp.Logging.LogSubscribers.FileSystem
{
    using SubhadraSolutions.Sharp.Logging.Common;
    using SubhadraSolutions.Sharp.Logging.Contracts;
    using SubhadraSolutions.Sharp.Utils.Data;
    using System.Collections.Generic;
    using System.IO;

    public abstract class AbstractStructuredFileLogSubscriber : AbstractFileLogSubscriber
    {
        #region Fields

        protected string fileEndingString = string.Empty;

        #endregion Fields

        #region Constructors

        protected AbstractStructuredFileLogSubscriber()
        {
            onlyAppendMode = false;
            Reader = new LogStoreItemDataReader();
        }

        #endregion Constructors

        #region Properties

        public ILoggerDataReader Reader
        {
            get;
            set;
        }

        #endregion Properties

        #region Methods

        protected virtual DataReaderDataTableAdapter getAdapter(IEnumerable<LogStoreItem> e)
        {
            if (e == null)
            {
                return null;
            }
            if (Reader != null)
            {
                Reader.SetEnumerator(e.GetEnumerator(), false);
                return new DataReaderDataTableAdapter(Reader, "Data");
            }
            return null;
        }

        protected override void initializeProtected()
        {
            setNewFileSizeThreshold();
            if (Reader != null)
            {
                Reader.SetProcessInstanceName(ProcessInstanceName);
                Reader.Initialize();
            }
            base.initializeProtected();
            writeResourceFiles();
        }

        protected override void publishLogs(StreamWriter writer, IEnumerable<LogStoreItem> e,
            bool isNewFile)
        {
            DataReaderDataTableAdapter adapter = getAdapter(e);
            if (adapter != null)
            {
                if (isNewFile)
                {
                    writeFileHeader(writer, adapter);
                }
                else
                {
                    if (newFileSizeThreshold != 0)
                    {
                        writer.BaseStream.Seek(-newFileSizeThreshold, SeekOrigin.Current);
                    }
                }
                writeRows(writer, adapter);
                writer.Write(fileEndingString);
            }
        }

        protected virtual void setNewFileSizeThreshold()
        {
            newFileSizeThreshold = Encoding == null
                ? fileEndingString.Length
                : Encoding.GetByteCount(fileEndingString);
        }

        protected abstract void writeFileHeader(StreamWriter writer,
            DataReaderDataTableAdapter adapter);

        protected virtual void writeResourceFiles()
        {
        }

        protected abstract void writeRows(StreamWriter writer, DataReaderDataTableAdapter adapter);

        #endregion Methods
    }
}